package com.jf.cloud.group.config.sharding;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 自定义复合分库策略算法
 * @author zz
 * @version 1.0
 */
public class CustomDatabaseComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {

    /**
     * 分片键优先级依次为：
     * order_id、user_id、refund_id
     * 维度，订单号、售后单号，他们的三个字段的后三位都是userid后三位
     *
     * 虽然是多字段路由，但最后都是取的userId的后三位
     *
     * @param dataSourceNames 数据源名称集合
     * @param shardingValue 分片键信息
     * @return 匹配的数据源集合
     */
    @Override
    public Collection<String> doSharding(Collection<String> dataSourceNames,
                                         ComplexKeysShardingValue<Long> shardingValue) {
        Collection<Long> groupOrderIds = shardingValue.getColumnNameAndShardingValuesMap().get("group_order_id");
        Collection<Long> ggroupActivityIds = shardingValue.getColumnNameAndShardingValuesMap().get("group_activity_id");
        Collection<Long> groupTeamIds = shardingValue.getColumnNameAndShardingValuesMap().get("group_team_id");
        // 有一个非常关键的企业级项目设计，单号，考虑好后续的分库分表的设计
        // 如果说没有之前的单号设计，这个时候你做分库分表就还是挺麻烦的，如何order维度和用户维度进行归一
        // 单号设计，起到了作用，把用户id后三位拼接为订单号的后三位，通过这个设计两个归一
        if (CollectionUtils.isNotEmpty(groupOrderIds)) {
            return getDatabaseNames(dataSourceNames, groupOrderIds);
        }
        if (CollectionUtils.isNotEmpty(ggroupActivityIds)) {
            return getDatabaseNames(dataSourceNames, ggroupActivityIds);
        }
        if (CollectionUtils.isNotEmpty(groupTeamIds)) {
            return getDatabaseNames(dataSourceNames, groupTeamIds);
        }
        return null;
    }

    /**
     * 获取数据源名
     * @param columnValues 分片键的值
     * @return 匹配的数据源集合
     */
    private Set<String> getDatabaseNames(Collection<String> dataSourceNames, Collection<Long> columnValues) {
        // 因为拿到的值可能是long类型
        List<String> columnValueStrs = columnValues.stream().map(String::valueOf).collect(Collectors.toList());
        Set<String> set = new HashSet<>();
        for(String columnValue : columnValueStrs) {
            // 获取用户ID后三位
            String valueSuffix = (columnValue.length() < 3) ? columnValue :
                    columnValue.substring(columnValue.length() - 3);
            String databaseSuffix = ShardingAlgorithmHelper.getDatabaseSuffix(Integer.parseInt(valueSuffix));
            for(String dataSourceName : dataSourceNames) {
                if(dataSourceName.endsWith(databaseSuffix)) {
                    set.add(dataSourceName);
                }
            }
        }
        return set;
    }

}
